package com.itranswarp.learnjava.practice.plugin.views;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLDecoder;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.Map;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.eclipse.core.runtime.IProgressMonitor;

public class Utils {

	public static Map<String, String> parseQueryString(String query) {
		String[] ss = query.split("&");
		Map<String, String> map = new HashMap<>();
		for (String s : ss) {
			try {
				int n = s.indexOf('=');
				if (n != (-1)) {
					String key = s.substring(0, n);
					String value = URLDecoder.decode(s.substring(n + 1), "UTF-8");
					map.put(key, value);
				}
			} catch (UnsupportedEncodingException e) {
			}
		}
		return map;
	}

	public static class HttpResponse {
		private static final byte[] EMPTY = new byte[0];

		public final int status;
		public final byte[] body;

		public HttpResponse(int status) {
			this.status = status;
			this.body = EMPTY;
		}

		public HttpResponse(int status, byte[] body) {
			this.status = status;
			this.body = body;
		}

		public boolean isOK() {
			return this.status / 100 == 2;
		}
	}

	public static HttpResponse http(String method, String url, IProgressMonitor monitor, InputStream dataInput,
			Map<String, String> headers) throws IOException {
		HttpsURLConnection conn = (HttpsURLConnection) new URL(url).openConnection();
//		if (url.startsWith("https://")) {
//			conn.setSSLSocketFactory(createSSLSocketFactory());
//		}
		conn.setRequestMethod(method);
		conn.setConnectTimeout(CONN_TIMEOUT);
		conn.setReadTimeout(READ_TIMEOUT);
		conn.setUseCaches(false);
		conn.setInstanceFollowRedirects(true);
		conn.setAllowUserInteraction(false);
		conn.setDoOutput(dataInput != null);
		conn.setRequestProperty("User-Agent",
				"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36");
		conn.setRequestProperty("Accept",
				"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8");
		conn.setRequestProperty("Accept-Language", "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7");
		if (headers != null) {
			for (String key : headers.keySet()) {
				conn.setRequestProperty(key, headers.get(key));
			}
		}
		OutputStream output = null;
		InputStream input = null;
		int code = -1;
		try {
			if (dataInput != null) {
				output = conn.getOutputStream();
				byte[] buffer = new byte[10240];
				int n = 0;
				while ((n = dataInput.read(buffer)) != (-1)) {
					output.write(buffer, 0, n);
				}
				output.flush();
			}
			if (monitor != null) {
				monitor.worked(10);
			}
			code = conn.getResponseCode();
			if (code / 100 != 2) {
				// error:
				input = conn.getErrorStream();
				if (input != null) {
					ByteArrayOutputStream byteArray = new ByteArrayOutputStream(4096);
					byte[] buffer = new byte[20480];
					int n = 0;
					while ((n = input.read(buffer)) != (-1)) {
						byteArray.write(buffer, 0, n);
						if (monitor != null) {
							monitor.worked(1);
						}
						if (monitor != null && monitor.isCanceled()) {
							throw new IOException("Canceled");
						}
					}
					return new HttpResponse(code, byteArray.toByteArray());
				}
				return new HttpResponse(code);
			}
			input = conn.getInputStream();
			byte[] buffer = new byte[4096];
			int n = 0;
			ByteArrayOutputStream byteArray = new ByteArrayOutputStream();
			while ((n = input.read(buffer)) != (-1)) {
				byteArray.write(buffer, 0, n);
			}
			return new HttpResponse(code, byteArray.toByteArray());
		} finally {
			if (output != null) {
				try {
					output.close();
				} catch (IOException e) {
				}
			}
			if (input != null) {
				try {
					input.close();
				} catch (IOException e) {
				}
			}
			conn.disconnect();
		}
	}

	static SSLSocketFactory createSSLSocketFactory() {
		TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
			@Override
			public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
			}

			@Override
			public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
			}

			@Override
			public X509Certificate[] getAcceptedIssuers() {
				return null;
			}
		} };

		try {
			SSLContext sslContext = SSLContext.getInstance("SSL");
			sslContext.init(null, trustAllCerts, new SecureRandom());
			return sslContext.getSocketFactory();
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	static final int CONN_TIMEOUT = 10000;
	static final int READ_TIMEOUT = 10000;

}
